#ifndef _SPRITE_SET_H_
#define _SPRITE_SET_H_

#include "graphics/image.h"
#include "num/named_set.h"
#include "math/vec2.h"
#include "graphics/surface.h"
#include <vector>            


namespace ui
{

struct	AtlasEntry;


struct	SpriteInstance
{
	static const int		MAX_FILENAME = 128;
	char			Name[MAX_FILENAME];
	char			ImageName[MAX_FILENAME];
	Image*			pImage;
	AtlasEntry*		pAtlasEntry;
	int				SpriteC;
	int				SpriteC_Row;
	float			FrameTime;
	float			ClipX, ClipY;
	math::Vec2		UV1, UV2;
	bool			ForceCache, FlipX, FlipY, VertFrames, Failed;
	int				Source;
	AlphaMask*		m_pMask;
	bool			ToSkipFrame;

	SpriteInstance() : m_pMask(NULL)
	{
		memset(this, 0, sizeof(SpriteInstance));
	}
	~SpriteInstance()
	{
		if (pImage) delete pImage;
		UTIL_SAFE_DELETE(m_pMask);
	}
	static	void SetString(char* Out, const std::string& In)		// simple utility
	{
		if (In.size() < MAX_FILENAME)
		{
			strcpy(Out, In.c_str());	// simple
		} else
		{
			memcpy(Out, &In[In.size()-(MAX_FILENAME+1)], MAX_FILENAME-1);
			Out[MAX_FILENAME-1] = '\0';
		}
	}

	bool			Init();
	bool			UpdateTime(int& LoopC, float& time, float dt, bool loop);
    void            GetUV(float Time, math::Vec2& UV1, math::Vec2& UV2);
    void            GetUV(unsigned int FrameID, math::Vec2& UV1, math::Vec2& UV2);
	void			GetFrameSize(math::Vec2& Size);
	float			GetAnimTime() const { return FrameTime*(float)SpriteC; }
	void			Flush();	// flush resource
	bool			HasMask() const { return m_pMask != NULL; };
	AlphaMask*		GetMask() const  { return m_pMask; };
	AlphaMask*		GenerateMask();

};

struct				AtlasEntry
{
	AtlasEntry() :pImage(0),x(0), y(0), w(0), h(0){};
	char			Name[SpriteInstance::MAX_FILENAME];
	Image*			pImage;
	int				PageIndex;
	int				x, y, w, h;
};
struct				AtlasInfo
{
	std::string		BaseName;
	int				Pages;
	int				Width, Height;
};

class SpriteSet : public num::NamedSet<SpriteInstance*>
{
public:

	static SpriteSet&	Instance();
	SpriteInstance*		GetSprite(const std::string& Sprite);
	void				AddSet(const std::string& File, bool TrackSet = true);	
	SpriteInstance*		AddSprite(	const std::string& Name, 
									const std::string& Image, 
									int SpriteC, 
									int SpriteC_Row, 
									float FrameTime, 
									float BorderX, 
									float BorderY, 
									bool FlipU, 
									bool FlipV, 
									float ClipC, 
									float ClipY, 
									bool	ForceCache, 
									int Source);

	void				Refresh();
	void				SetDeferLoading(bool b) { m_DeferLoading = b; };
	void				LoadAtlas(const std::string& Atlas);
	AtlasEntry*			GetAtlas(const std::string& Name) { return m_Atlas.GetElement(Name); };
	void				SetClamp(float Val) { m_Clamp = Val; };
	float				GetClamp()  const { return m_Clamp; };
private:
	SpriteSet();
	~SpriteSet();
    SpriteSet( const SpriteSet& );     
    SpriteSet & operator=( const SpriteSet & );

	std::vector<std::string>		m_SpriteSetsLoaded;
	bool							m_DeferLoading;
	float							m_Clamp;

	// texture atlas
	
	AtlasInfo						m_AtlasInfo;
	num::NamedSet<AtlasEntry*>		m_Atlas;
};


} // namespace ui


#endif // _SPRITE_SET_H_